package org.phantom.securityframework.datapermission;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;

import javax.annotation.Resource;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.phantom.securityframework.api.exception.AnnotationConfigureException;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;


/**
 * aop切面,对需要进行数据过滤的resource进行拦截,拦截后根据配置的provider进行数据筛选,
 * 筛选出来的数据会注入给controller的QueryResult参数.由controller执行数据输出
 * 所以,需要进行数据权限过滤的controller必须要有一个QueryResult参数
 * 
 * @see org.phantom.securityframework.api.datapermission.QueryResult
 * @see org.phantom.securityframework.api.datapermission.DataProvider
 */

@Aspect
@Component
public class DataFilterAspect {
	

	@Resource
	private DataProviderResolver dataProviderResolver = null;
	
	/**
	 * 定义切入点
	 * 所有标注了org.phantom.securityframework.api.datapermission.DataFilter的方法,都会被拦截
	 */
	@Pointcut("@annotation(org.phantom.securityframework.api.datapermission.DataFilter)")
	public void pointcut(){}
	
	
	/**
	 * 定义环绕切面
	 * 1.根据配置创建DataProvider
	 * 2.执行查询
	 * 3.注入查询结果
	 * 
	 * @see org.phantom.securityframework.api.datapermission.DataProvider
	 * @see org.phantom.securityframework.api.datapermission.QueryResult
	 * @param point
	 * @return
	 * @throws Throwable 
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Around("pointcut()")
	public Object aspect(ProceedingJoinPoint point) throws Throwable{
		DataProvider provider = this.buildDataProvider(point);
		if(provider ==null)
			throw new AnnotationConfigureException(String.format("error creating provider where name '%s',because not found!",this.resolveAnnotation(point).value()));
		Annotation anno = this.resolveAnnotation(point);
		QueryResult result = new QueryResult(provider.total(point.getArgs(),anno), (List) provider.provide(point.getArgs(),anno)); 
		Object[] o = this.injectResult(result,point);

		Object returnVal = point.proceed(o);
		return returnVal;
	}
	
	/**
	 * 注入查询结果
	 * 由框架进行查询,查询完成后将结果注入给QueryResult参数
	 * @see org.phantom.securityframework.api.datapermission.QueryResult
	 * @param r
	 * @param point
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	protected Object[] injectResult(QueryResult r,ProceedingJoinPoint point) {
		Object[] o = point.getArgs();
		MethodSignature signature = (MethodSignature) point.getSignature();
		Class<?>[] classes = signature.getMethod().getParameterTypes();
		for (int i=0;i<classes.length;i++) {
			if(classes[i].getName().equals(r.getClass().getName())){
				o[i]=r;
			}
		}
		return o;
	}
	
	/**
	 * 创建dataProvider,如果DataFilter所配为空,则返回缺省的框架内置provider
	 * @see org.phantom.securityframework.api.datapermission.DataProvider
	 * @param point
	 * @return
	 * @throws Exception
	 */
	protected DataProvider buildDataProvider(JoinPoint point){
		DataFilter filter = this.resolveAnnotation(point);
		if(null!=filter.mapper() && filter.mapper().length>0){
			if(!filter.mapper()[0].equals(""))
			return dataProviderResolver.resolveDataProvider(DataProviderResolver.MAPPER_PROVIDER);
		}
		return dataProviderResolver.resolveDataProvider(filter.value());
	}

	/**
	 * 获取注解配置
	 * @see org.phantom.securityframework.api.datapermission.DataFilter
	 * @param point
	 * @return
	 */
	protected DataFilter resolveAnnotation(JoinPoint point){
		Method method = this.resolveMethod(point);
		return AnnotationUtils.findAnnotation(method, DataFilter.class);
	}
	
	protected Method resolveMethod(JoinPoint point){
		 Method[] m = point.getTarget().getClass().getDeclaredMethods();
		 for (Method method : m) {
			if(method.getName().equals(point.getSignature().getName()))
				return method;
		}
		return null;
	}
}
